import json
import logging
import time

import requests
import base64
from celery import shared_task
from urllib.parse import quote
from django.conf import settings
from .myredis import r
from .baidu import BaiduApi

logger = logging.getLogger(__name__)


class BaiduOCRService:
    def __init__(self):
        self.api = BaiduApi()

    def recognize_id_card(self, image_url):
        """身份证识别方法"""
        try:
            # 下载图片
            session = requests.Session()
            adapter = requests.adapters.HTTPAdapter(max_retries=3)
            session.mount('http://', adapter)
            session.mount('https://', adapter)

            image_response = session.get(
                image_url,
                timeout=30,
                verify=settings.VERIFY_SSL  # 从配置读取
            )
            image_response.raise_for_status()

            # 转换为base64
            image_base64 = base64.b64encode(image_response.content).decode()

            # 调用百度OCR
            return self.api.idcard(image_base64)
        except Exception as e:
            logger.error(f"身份证识别失败: {str(e)}")
            return {"code": 500, "msg": f"识别失败: {str(e)}"}


@shared_task(
    bind=True,
    name='id_card_recognition_task',
    autoretry_for=(Exception,),
    retry_backoff=True,
    max_retries=3
)
def id_card_recognition_task(self, image_url, user_id):
    """异步身份证识别任务"""
    logger.info(f"开始处理身份证识别任务: {image_url[:50]}...")

    # 状态跟踪键
    status_key = f"ocr_status:{self.request.id}"
    result_key = f"ocr_result:{self.request.id}"

    try:
        # 更新状态为处理中
        r.setex(status_key, 3600, "processing")

        # 执行识别
        ocr_service = BaiduOCRService()
        result = ocr_service.recognize_id_card(image_url)

        # 存储结果
        result_data = {
            "image_url": image_url,
            "user_id": user_id,
            "result": result,
            "task_id": self.request.id
        }
        r.setex(result_key, 86400, json.dumps(result_data))

        # 更新状态
        r.setex(status_key, 3600, "completed")
        logger.info(f"身份证识别任务完成: {self.request.id}")

        return result
    except Exception as e:
        logger.exception(f"身份证识别任务失败: {str(e)}")
        r.setex(status_key, 3600, f"failed:{str(e)}")
        raise self.retry(exc=e)


@shared_task(
    name='text_recognition_task',
    autoretry_for=(Exception,),
    retry_backoff=True,
    max_retries=3
)
def text_recognition_task():
    """
    百度文字识别Celery定时任务
    1. 从Redis队列获取待识别的图片URL
    2. 调用百度文字识别API
    3. 将结果存储到Redis结果队列
    """
    logger = text_recognition_task.get_logger()

    try:
        # 配置参数
        queue_key = 'baidu:image:queue'
        result_key = 'baidu:recognition:results'
        error_key = 'baidu:recognition:errors'
        batch_size = 10

        logger.info(f"Starting text recognition task. Processing {batch_size} images.")

        # 原子操作：获取并移除队列中的URL
        urls = r.lpop(queue_key, count=batch_size) or []

        if not urls:
            logger.info("No images in queue. Task completed.")
            return {"status": "success", "processed": 0}

        processed_count = 0
        for url_bytes in urls:
            try:
                original_url = url_bytes.decode('utf-8')
                encoded_url = quote(original_url, safe='/:?=&')

                # 调用百度文字识别API
                result = BaiduApi().fontmessage(encoded_url)

                # 构建结果对象
                result_data = {
                    "url": original_url,
                    "timestamp": int(time.time()),
                    "recognition_result": result,
                    "success": "name" in result and "code" in result
                }

                # 存储到Redis结果队列
                r.rpush(result_key, json.dumps(result_data))

                processed_count += 1
                logger.debug(f"Processed URL: {original_url[:50]}...")

            except Exception as e:
                logger.error(f"Error processing URL: {str(e)}")
                r.rpush(error_key, url_bytes)

        logger.info(f"Task completed. Processed {processed_count}/{len(urls)} images.")
        return {
            "status": "success",
            "processed": processed_count,
            "failed": len(urls) - processed_count
        }

    except Exception as e:
        logger.exception(f"Text recognition task failed: {str(e)}")
        raise